package com.wym.exampleproject.distributedredislock.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class BaseService {

    @Autowired
    public StringRedisTemplate stringRedisTemplate;


    public boolean lock1(String key, String lock, int timeout){
        boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, lock);
        if(!flag){
            if(log.isDebugEnabled()){
                log.debug("Don't get redis lock.[{}]", getName());
            }
            return flag;
        }
        /**
         * 拿到锁设置锁key的超时时间
         */
        stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);
        if(log.isDebugEnabled()){
            log.debug("Get redis lock.[{}]", getName());
        }
        return flag;
    }

    private String getName() {
        return this.getClass().getName();
    }


    public boolean lock2(String key, int timeout){
        //锁的值为当前时间+超时时间
        long lockValue = System.currentTimeMillis() + timeout;
        if(stringRedisTemplate.opsForValue().setIfAbsent(key, String.valueOf(lockValue))) {
            return true;
        }
        //其他人获取不到锁执行如下代码
        //获取锁的值
        String currentLockValue = stringRedisTemplate.opsForValue().get(key);

        //锁的值小于当前时则锁已过期
        if (!StringUtils.isEmpty(currentLockValue) && Long.parseLong(currentLockValue) < System.currentTimeMillis()) {
            //getAndSet线程安全所以只会有一个线程重新设置锁的新值
            String oldValue = stringRedisTemplate.opsForValue().getAndSet(key, String.valueOf(lockValue));
            //比较锁的getSet获取到的最近锁值和最开始获取到的锁值，如果不相等则证明锁已经被其他线程获取了。
            if (!StringUtils.isEmpty(oldValue) && oldValue.equals(currentLockValue)) {
                return true;
            }
        }
        return false;
    }

    public void unLock(String key){
        stringRedisTemplate.delete(key);
    }
}
